import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpEchoServer {
    private DatagramSocket socket = null;

    public UdpEchoServer(int port) throws SocketException {
        // 创建一个 DatagramSocket 对象，用于发送和接收 UDP 数据报
        //指定一个固定端口号， 让服务器来使用
        socket = new DatagramSocket(port);
    }

    public void start() throws IOException {
        //启动服务器
        System.out.println("服务器启动成功： ");

        // 循环接收数据报
        while (true) {
            //循环一次就相当于处理了一次请求
            //处理请求的过程，典型的服务器都分成三个步骤：
            //1.读取请求并解析
            // DatagramPacket 表示一个 UDP 数据报， 此处传入的字节数组，就保存UDP的载荷部分
            DatagramPacket requestPackage = new DatagramPacket(new byte[4096], 4096);
            socket.receive(requestPackage);
            //把读取的二进制数据 转换成字符串 只构造有效部分
            String request = new String(requestPackage.getData(), 0, requestPackage.getLength());

            //2.根据请求 计算响应(服务器关键逻辑)
            //此处是写的是回显(Echo)服务器， 这个处理环节就相当于省略了
            String response = process(request);//用方法封装处理逻辑

            //3.发送响应到客户端
            //根据response构造一个新的 DatagramPacket包， 并发送给客户端
            //此处不能使用response.getlength()，因为response可能包含中文字符，会导致长度不一致，导致发送失败(因为长度不匹配)
            DatagramPacket responsePackage = new DatagramPacket(response.getBytes(), response.getBytes().length,
                    requestPackage.getSocketAddress());//或的端口号和IP地址
            //此处不能直接发送 UDP协议自身没有保存对方的地址信息和端口号(不知道发给谁)
            //需要指定的目的ip和端口号
            socket.send(responsePackage);

            //4.打印一个日志
            System.out.printf("[%s:%d] req: %s, resq: %s\n", requestPackage.getAddress().toString(), requestPackage.getPort(),
                            request, response);

        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();
    }
}
